home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / jsmodules / SBJobUtils.jsm < prev    next >
Text File  |  2008-08-06  |  10KB  |  312 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. // 
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. // 
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. // 
  13. // Software distributed under the License is distributed 
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
  15. // express or implied. See the GPL for the specific language 
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this 
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc., 
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. // 
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. EXPORTED_SYMBOLS = [ "SBJobUtils" ];
  28.  
  29. // Amount of time to wait before launching a progress dialog
  30. const PROGRESS_DEFAULT_DIALOG_DELAY = 1000;
  31.  
  32. const Cc = Components.classes;
  33. const Ci = Components.interfaces;
  34. const Cr = Components.results;
  35. const Ce = Components.Exception;
  36. const Cu = Components.utils;
  37.  
  38. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  39. Cu.import("resource://app/jsmodules/ArrayConverter.jsm");
  40. Cu.import("resource://app/jsmodules/WindowUtils.jsm");
  41. Cu.import("resource://app/jsmodules/SBTimer.jsm");
  42.  
  43.  
  44. /******************************************************************************
  45.  * A collection of functions for manipulating sbIJob* interfaces
  46.  *****************************************************************************/
  47. var SBJobUtils = {
  48.  
  49.   /**
  50.    * \brief Display a progress dialog for an object implementing sbIJobProgress.
  51.    *
  52.    * If the job has not completed in a given amount of time, display
  53.    * a modal progress dialog. 
  54.    *
  55.    * \param aJobProgress    sbIJobProgress interface to be displayed.
  56.    * \param aWindow         Parent window for the dialog. Can be null.
  57.    * \param aTimeout        Time to wait before opening a dialog. 
  58.    *                        Defaults to 1 second.  Pass 0 to open 
  59.    *                        the dialog immediately.
  60.    */
  61.   showProgressDialog: function(aJobProgress, aWindow, aTimeout) {
  62.     if (!(aJobProgress instanceof Ci.sbIJobProgress)) {
  63.       throw new Error("showProgressDialog requires an object implementing sbIJobProgress");
  64.     }
  65.  
  66.     function showDialog() {
  67.       if (timer) {
  68.         timer.cancel();
  69.         timer = null;
  70.       }
  71.       
  72.       // If the job is already complete, skip the dialog
  73.       if (aJobProgress.status == Ci.sbIJobProgress.STATUS_SUCCEEDED) {
  74.         return;
  75.       }
  76.      
  77.       // Parent to the main window by default
  78.       if (!aWindow || aWindow.closed) {
  79.         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  80.                            .getService(Components.interfaces.nsIWindowMediator);
  81.         aWindow = wm.getMostRecentWindow("Songbird:Main");
  82.       }
  83.       
  84.       // Otherwise, launch the dialog  
  85.       WindowUtils.openModalDialog(
  86.          aWindow,
  87.          "chrome://songbird/content/xul/jobProgress.xul",
  88.          "job_progress_dialog",
  89.          "chrome,centerscreen",
  90.          [ aJobProgress ],
  91.          null,
  92.          null);
  93.     } 
  94.    
  95.     if (aTimeout == null) {
  96.       aTimeout = PROGRESS_DEFAULT_DIALOG_DELAY;
  97.     }
  98.     
  99.     var timer;
  100.     if (aTimeout) {
  101.       // Wait a bit before launching the dialog.  If the job is already
  102.       // complete don't bother launching it.
  103.       // The timer will maintain a ref to this closure during the delay, and vice versa.
  104.       timer = new SBTimer(showDialog, aTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
  105.     } else {
  106.       // If 0 just show immediately
  107.       showDialog();
  108.     }
  109.   }
  110.   
  111. }
  112.  
  113.  
  114. /******************************************************************************
  115.  * A base implementation of sbIJobProgress, to be extended
  116.  * when creating a JavaScript sbIJobProgress object.
  117.  *
  118.  * Supports forwarding progress information to a child sbIJobProgress,
  119.  * for cases where a main job needs to aggregate a number of sub-jobs.
  120.  *
  121.  * See DirectoryImportJob for an example.
  122.  *****************************************************************************/
  123. SBJobUtils.JobBase = function() {
  124.   this._errorMessages = [];
  125.   this._listeners = [];
  126. }
  127. SBJobUtils.JobBase.prototype = {
  128.   QueryInterface          : XPCOMUtils.generateQI(
  129.       [Ci.sbIJobProgress, Ci.sbIJobCancelable, 
  130.        Ci.sbIJobProgressListener, Ci.nsIClassInfo]),
  131.  
  132.   /** nsIClassInfo, so callers don't have to QI from JS **/
  133.   
  134.   classDescription        : 'Songbird Job Progress Implementation',
  135.   classID                 : null,
  136.   contractID              : null,
  137.   flags                   : Ci.nsIClassInfo.MAIN_THREAD_ONLY,
  138.   implementationLanguage  : Ci.nsIProgrammingLanguage.JAVASCRIPT,
  139.   getHelperForLanguage    : function(aLanguage) { return null; },
  140.   getInterfaces : function(count) {
  141.     var interfaces = [Ci.sbIJobProgress,
  142.                       Ci.sbIJobCancelable,
  143.                       Ci.sbIJobProgressListener,
  144.                       Ci.nsIClassInfo,
  145.                       Ci.nsISupports
  146.                      ];
  147.     count.value = interfaces.length;
  148.     return interfaces;
  149.   },
  150.  
  151.   
  152.   _status              : Ci.sbIJobProgress.STATUS_RUNNING,
  153.   _statusText          : "",
  154.   _titleText           : "",
  155.   _progress            : 0,
  156.   _total               : 0,
  157.   
  158.   // Array of error strings
  159.   _errorMessages       : null,
  160.   
  161.   // Array of listeners
  162.   _listeners           : null,
  163.   
  164.   // Another sbIJobProgress. If set, all sbIJobProgress calls other than
  165.   // status and listeners will be forwarded through to the other job.
  166.   // This can be used to provide a single interface that aggregates
  167.   // several sub-jobs.
  168.   _jobProgressDelegate : null,
  169.   
  170.   
  171.   /** sbIJobProgress **/
  172.   
  173.   get status() {
  174.     // Note that status is not delegated, as the main job only completes
  175.     // when all sub-jobs are finished.
  176.     return this._status;
  177.   },
  178.   
  179.   get statusText() {
  180.     return (this._jobProgressDelegate) ? 
  181.       this._jobProgressDelegate.statusText : this._statusText;
  182.   },
  183.   
  184.   get titleText() {
  185.     return (this._jobProgressDelegate) ? 
  186.       this._jobProgressDelegate.titleText : this._titleText;
  187.   },
  188.   
  189.   get progress() {
  190.     return (this._jobProgressDelegate) ? 
  191.       this._jobProgressDelegate.progress : this._progress;
  192.   },
  193.   
  194.   get total() {
  195.     return (this._jobProgressDelegate) ? 
  196.       this._jobProgressDelegate.total : this._total;
  197.   },
  198.   
  199.   get errorCount() {
  200.     return (this._jobProgressDelegate) ? 
  201.       this._jobProgressDelegate.errorCount : this._errorMessages.length;
  202.   },
  203.   
  204.   getErrorMessages: function Job_getErrorMessages() {
  205.     return (this._jobProgressDelegate) ? 
  206.       this._jobProgressDelegate.getErrorMessages() :
  207.       ArrayConverter.enumerator(this._errorMessages);
  208.   },
  209.   
  210.   addJobProgressListener: function Job_addJobProgressListener(aListener) {
  211.     aListener.QueryInterface(Ci.sbIJobProgressListener);
  212.     this._listeners.push(aListener);
  213.   },
  214.   
  215.   removeJobProgressListener: function Job_removeJobProgressListener(aListener){
  216.     var index = this._listeners.indexOf(aListener);
  217.     if (index > -1) {
  218.       this._listeners.splice(index,1);
  219.     }
  220.   },
  221.   
  222.   
  223.   /** sbIJobCancelable **/
  224.   
  225.   _canCancel: false,
  226.   get canCancel() {
  227.     return (this._jobProgressDelegate && 
  228.             this._jobProgressDelegate instanceof Ci.sbIJobCancelable) ? 
  229.               this._jobProgressDelegate.canCancel : this._canCancel;
  230.   },
  231.   
  232.   cancel: function Job_cancel() {
  233.     // Override this method
  234.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  235.   },
  236.   
  237.   
  238.   /** Non-interface methods **/
  239.   
  240.   /**
  241.    * Delegate most of sbIJobProgress to the given sub-job.
  242.    * Allows this job to wrap/aggregate other jobs.
  243.    * Pass null to stop delegation.
  244.    */
  245.   delegateJobProgress: function Job_delegateJobProgress(aJob)  {
  246.     if (aJob != null && !(aJob.QueryInterface(Ci.sbIJobProgress))) {
  247.       throw Components.results.NS_ERROR_INVALID_ARG;
  248.     }
  249.     
  250.     if (this._jobProgressDelegate) {
  251.       this._jobProgressDelegate.removeJobProgressListener(this);
  252.     }
  253.     
  254.     this._jobProgressDelegate = aJob;
  255.     
  256.     if (this._jobProgressDelegate) {
  257.       this._jobProgressDelegate.addJobProgressListener(this);
  258.     }
  259.   },
  260.  
  261.  
  262.   /**
  263.    * sbIJobProgressListener implementation. Called by 
  264.    * _jobProgressDelegate if set.
  265.    */
  266.   onJobProgress: function Job_onJobProgress(aJob) {
  267.     if ((!this._jobProgressDelegate) || this._jobProgressDelegate != aJob) {
  268.       // Just report the error. Don't throw, as that would just go to the
  269.       // sub-job, and wouldn't help.
  270.       Cu.reportError("Job_onJobProgress called with invalid _jobProgressDelegate state!");
  271.     }
  272.     
  273.     // Forward the progress notification on to all our listeners
  274.     this.notifyJobProgressListeners();
  275.     
  276.     // If the delegate is done, allow the main job to move on
  277.     if (this._jobProgressDelegate.status != Ci.sbIJobProgress.STATUS_RUNNING) {
  278.       this.onJobDelegateCompleted();
  279.     }
  280.   },
  281.   
  282.   
  283.   /**
  284.    * Called when a sub-job (set with delegateJobProgress) completes.
  285.    * Override this method to carry on with other work.
  286.    */
  287.   onJobDelegateCompleted: function Job_onJobDelegateCompleted() {
  288.     // Base behaviour is to just throw away the delegated job
  289.     this.delegateJobProgress(null);
  290.   },
  291.  
  292.  
  293.   /**
  294.    * Poke listeners and tell them to check the current progress
  295.    */  
  296.   notifyJobProgressListeners: function Job_notifyJobProgressListeners() {
  297.     var thisJob = this;
  298.     // need to clone the array, otherwise removing one in the middle gets
  299.     // things confused
  300.     var listeners = [].concat(this._listeners);
  301.     listeners.forEach( function (listener) {
  302.       try {
  303.         listener.onJobProgress(thisJob);
  304.       } catch (e) {
  305.         Cu.reportError(e);
  306.       }
  307.     });
  308.   }
  309. }
  310.  
  311.  
  312.